/**
 * Copyright [2019] [LiBo/Alex of copyright liboware@gmail.com ]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.metrics.toolkit.gauges;

import com.codahale.metrics.*;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @project-name:coffice-toolbox
 * @package-name:com.hyts.metrics.toolkit
 * @author:LiBo/Alex
 * @create-date:2020-05-11 12:13
 * @copyright:libo-alex4java
 * @email:liboware@gmail.com
 * @description:
 *
 * 通过以上步骤将会向MetricsRegistry容器中注册一个名字为com.netease.test.metrics.TestGauges.pending-job.size的metrics，实时获取队列长度的指标。
 * 另外，Core包种还扩展了几种特定的Gauge：
 * JMX Gauges—提供给第三方库只通过JMX将指标暴露出来。
 * Ratio Gauges—简单地通过创建一个gauge计算两个数的比值。
 * Cached Gauges—对某些计量指标提供缓存
 * Derivative Gauges—提供Gauge的值是基于其他Gauge值的接口。
 */
@Slf4j
public class GaugesService {

    /**
     * 实例化一个registry，最核心的一个模块，相当于一个应用程序的metrics系统的容器，维护一个Map
     */
    private static final MetricRegistry metrics = new MetricRegistry();

    /**
     * 在控制台上打印输出
     */
    private ScheduledReporter reporter;

    /**
     * 操作统计服务
     */
    JmxReporter jmxReporter;

    /**
     * 默认构造器
     */
    public GaugesService(){
        this(ConsoleReporter.forRegistry(metrics).build());
    }


    public GaugesService(ScheduledReporter reporter){
        Objects.requireNonNull(reporter,"传入的SchedulerReporter对象不允许为空!");
        this.reporter = reporter;
    }

    public GaugesService start(Supplier<?> supplier){
        return start(1,TimeUnit.SECONDS,supplier, UUID.randomUUID().toString());
    }

    /**
     * 一秒统计操作
     * @param supplier
     * @param metricsName
     * @return
     */
    public GaugesService start(Supplier<?> supplier,String... metricsName){
        return start(1,TimeUnit.SECONDS,supplier,metricsName);
    }

    /**
     * 启动
     * @param timeInterval
     * @param metricsName
     * @return
     */
    public GaugesService start(int timeInterval,Supplier<?> supplier,String... metricsName){
       return start(timeInterval,TimeUnit.SECONDS,supplier,metricsName);
    }

    /**
     * 启动时间间隔
     * @param timeInterval
     * @param timeUnit
     */
    public GaugesService start(int timeInterval, TimeUnit timeUnit, Supplier<?> supplier,String... metricsName){
        Objects.requireNonNull(supplier,"传入的监控数据对象不允许为空!");
        //启动服务报告线程处理
        reporter.start(timeInterval, timeUnit);
        //实例化一个Gauge
        Gauge<?> gauge = supplier::get;
        //注册到容器中
        metrics.register(MetricRegistry.name("coffice-toolbox-metrics-Gauges-Job", metricsName), gauge);
        //测试JMX
        jmxReporter = JmxReporter.forRegistry(metrics).build();
        Objects.requireNonNull(jmxReporter,"传入的jmxReporter不允许为空!");
        jmxReporter.start();
        return this;
    }

    /**
     * 处理操作
     * @return
     */
    public GaugesService stop(){
        try {
            reporter.stop();
            if(Objects.nonNull(jmxReporter)){
                jmxReporter.stop();
            }
        } catch (Exception e) {
            log.error("停止统计失败!",e);
            return this;
        }
        return this;
    }

    /**
     * 关闭操作
     * @return
     */
    public boolean close(){
        try {
            reporter.close();
            if(Objects.nonNull(jmxReporter)){
                jmxReporter.close();
            }
        } catch (Exception e) {
            log.error("关闭统计失败!",e);
            return false;
        }
        return true;
    }


    /**
     * 主体main方法执行
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        //模拟数据
        GaugesService gaugesService = new GaugesService();
        MemoryUsageGaugeSet queue = new MemoryUsageGaugeSet();
        gaugesService.start(()->(Metric)queue.getMetrics().get("total.used"));
        for (int i=0; i<20; i++){
            //System.out.println(queue.getMetrics());
            Thread.sleep(500);
        }
    }
}
